package com.coco.group.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.coco.common.alipayparam.PayVo;
import com.coco.common.constant.Constant;
import com.coco.common.constant.GroupBuyEnum;
import com.coco.common.constant.TYPE;
import com.coco.common.result.CommonResponse;
import com.coco.common.util.IdWorker;
import com.coco.common.util.RandomString;
import com.coco.group.feign.AlipayFeign;
import com.coco.group.mapper.GroupBuyGoodsMapper;
import com.coco.group.mapper.GroupBuyItemMapper;
import com.coco.group.mapper.GroupBuyRecordMapper;
import com.coco.group.mapper.GroupOrderMapper;
import com.coco.group.pojo.TbGroupBuyGoods;
import com.coco.group.pojo.TbGroupBuyItem;
import com.coco.group.pojo.TbGroupBuyRecord;
import com.coco.group.pojo.TbGroupOrder;
import com.coco.group.service.GroupBuyGoodsService;
import com.coco.group.service.GroupBuyService;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.lettuce.core.codec.StringCodec;
import io.swagger.models.auth.In;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.apache.curator.utils.CloseableUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PreDestroy;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author minicoco
 * @version 1.0
 * @date 2021/7/30 14:15
 * 拼团服务层
 */
@Slf4j
@Service
public class GroupBuyServiceImpl implements GroupBuyService {

    @Autowired
    private IdWorker idWorker;
    @Autowired
    private GroupBuyGoodsMapper goodsMapper;
    @Autowired
    private GroupBuyItemMapper itemMapper;
    @Autowired
    private GroupOrderMapper orderMapper;
    @Autowired
    private GroupBuyRecordMapper recordMapper;
    @Autowired
    private AlipayFeign alipayFeign;
    /**
     * 注入Curator
     */
    @Autowired
    private CuratorFramework curatorFramework;
    /**
     * 读取锁路径
     */
    @Value("${zk.localPath}")
    private String lockPath;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    /**
     * redis
     */
    private RedisTemplate redisTemplate;
    @Autowired(required = false)
    public void setRedisTemplate(RedisTemplate redisTemplate) {
        //Json 序列化配置
        Jackson2JsonRedisSerializer objectJackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        objectJackson2JsonRedisSerializer.setObjectMapper(om);

        RedisSerializer stringSerializer = new StringRedisSerializer();
        redisTemplate.setKeySerializer(stringSerializer);
        redisTemplate.setValueSerializer(objectJackson2JsonRedisSerializer);
        redisTemplate.setHashKeySerializer(stringSerializer);
        redisTemplate.setHashValueSerializer(objectJackson2JsonRedisSerializer);
        this.redisTemplate = redisTemplate;
    }


    /**
     * 发起拼团
     * @param itemId skuId
     * @param uid 用户id
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public String startGroupBuy(Long itemId, Long uid) {
        Map itemMap = redisTemplate.opsForHash().entries("group_goods:" + itemId);
        //1.判断当前用户是否有未支付的订单
        TbGroupOrder groupOrder = orderMapper.findByUserIdAndStatus(uid, Constant.OrderStatus.STATUS_ONE.toString());
        if (!ObjectUtils.isEmpty(groupOrder)){
            return GroupBuyEnum.ORDER_NO_PAY.getMessage();
        }
        //判断当前时间活动是否开始
        if ((Long)itemMap.get("startTime")>System.currentTimeMillis()){
            //活动未开始
            return GroupBuyEnum.ACTIVITY_NOT_START.getMessage();
        }else if ((Long)itemMap.get("endTime")<System.currentTimeMillis()){
            //活动已结束
            return GroupBuyEnum.ACTIVITY_IS_OVER.getMessage();
        }else {
            String orderId = null;
            try {
                //发起拼团
                //判断商品库存是否足够
                if ((Integer)itemMap.get("limitResidue")<(Integer) itemMap.get("personNum")){
                    //商品库存不满足开团条件
                    return GroupBuyEnum.UNDER_STOCK.getMessage();
                }
                //取出用户购买次数
                Map userGoodsNum = redisTemplate.opsForHash().entries("group_goods_num:" + itemId);
                if (userGoodsNum==null){
                    //当前是第一个用户访问
                    userGoodsNum = new HashMap<>();
                    userGoodsNum.put("userId:"+uid,1);
                    redisTemplate.opsForHash().putAll("group_goods_num:" + itemId,userGoodsNum);
                }else {
                    //当前用户第一次访问
                    if (userGoodsNum.get("userId:"+uid)==null){
                        userGoodsNum.put("userId:"+uid,1);
                        redisTemplate.opsForHash().putAll("group_goods_num:" + itemId,userGoodsNum);
                    }
                }
                //获取购买次数限制
                int buyLimit = (int) itemMap.get("buyLimit");
                //获取当前用户的购买次数
                int userNum = (int) userGoodsNum.get("userId:" + uid);
                //判断当前用户购买次数是否超出限制
                if(userNum>=buyLimit){
                    return Constant.GroupBuyConstant.OVER_LIMIT;
                }
                //锁定商品库存
                Integer limitResidue = (Integer) itemMap.get("limitResidue");
                limitResidue -=1;
                itemMap.put("limitResidue",limitResidue);
                redisTemplate.opsForHash().putAll("group_goods:" + itemId,itemMap);
                //创建订单
                orderId = idWorker.nextId()+"";
                //生成邀请码
                String random = RandomString.getRandom(24, TYPE.CAPITAL);
                TbGroupOrder order = createGroupOrder(itemId,uid, itemMap, orderId,Constant.GroupBuyConstant.IS_HEADER,random);
                //拉起支付
                String html = pullUpToPay(itemMap, orderId);
                return html;
            } catch (Exception e) {
                e.printStackTrace();
            }
            return "支付失败!";
        }
    }

    /**
     * 添加拼团商品进入redis
     */
    @Override
    public void addGroupGoodsToRedis() {
        //查询可以拼团的商品
        List<TbGroupBuyGoods> groupBuyGoods = goodsMapper.findStartGroupGoods();
        //加入redis
        groupBuyGoods.forEach(item ->{
            List<TbGroupBuyItem> byGoodsId = itemMapper.findByGoodsId(item.getId());
            byGoodsId.forEach(entity -> {
                HashMap<String, Object> map = new HashMap<>();
                map.put("startTime",item.getStartTime().getTime());
                map.put("endTime",item.getEndTime().getTime());
                map.put("limitResidue",entity.getLimitResidue());
                map.put("groupPrice",entity.getGroupPrice());
                map.put("personNum",item.getPersonNum());
                map.put("timeLimit",item.getTimeLimit());
                map.put("joinNum",item.getJoinNum());
                map.put("buyLimit",item.getBuyLimit());
                map.put("goodsId",item.getId());
                map.put("goodsName",item.getName());
                redisTemplate.opsForHash().putAll("group_goods:"+entity.getId(),map);
            });
        });
    }

    /**
     * 参与拼团
     * @param code 邀请码
     * @param uid
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public String joinGroup(String code, Long uid) throws Exception {
        //通过邀请码得到拼团记录
        String object = (String) redisTemplate.opsForValue().get(Constant.GroupBuyConstant.REDIS_GROUP_RECORD+code);
        TbGroupBuyRecord record = JSON.parseObject(object, TbGroupBuyRecord.class);
        if (record==null){
            return Constant.GroupBuyConstant.GROUP_BUY_OVER;
        }
        //1.判断当前用户是否有未支付的订单
        TbGroupOrder groupOrder = orderMapper.findByUserIdAndStatus(uid, Constant.OrderStatus.STATUS_ONE.toString());
        if (!ObjectUtils.isEmpty(groupOrder)){
            return GroupBuyEnum.ORDER_NO_PAY.getMessage();
        }
        //获取当前商品的限制
        Map map = redisTemplate.opsForHash().entries("group_goods:" + record.getGroupBuyItemId());


        //当前参团人数
        Integer personNum = (Integer) map.get("personNum");
        if (record.getJoinNum()>=personNum){
            return Constant.GroupBuyConstant.PERSON_NUM_ENOUGH;
        }
        /**
         * 添加zk分布式锁
         */
        InterProcessMutex mutex = new InterProcessMutex(curatorFramework,lockPath+record.getGroupBuyItemId());
        try {
            boolean locked =mutex.acquire(0,TimeUnit.SECONDS);
            log.info("开始上锁,获取锁状态:{}",locked);
            //取出用户购买次数
            Map userGoodsNum = redisTemplate.opsForHash().entries("group_goods_num:" + record.getGroupBuyItemId());
            if (userGoodsNum==null){
                //当前是第一个用户访问
                userGoodsNum = new HashMap<>(16);
                userGoodsNum.put("userId:"+uid,1);
                redisTemplate.opsForHash().putAll("group_goods_num:" + record.getGroupBuyItemId(),userGoodsNum);
            }else {
                //当前用户第一次访问
                if (userGoodsNum.get("userId:"+uid)==null){
                    userGoodsNum.put("userId:"+uid,1);
                    redisTemplate.opsForHash().putAll("group_goods_num:" + record.getGroupBuyItemId(),userGoodsNum);
                }
            }
            //获取购买次数限制
            int buyLimit = (int) map.get("buyLimit");
            //获取当前用户的购买次数
            int userNum = (int) userGoodsNum.get("userId:" + uid);
            //判断当前用户购买次数是否超出限制
            if(userNum>=buyLimit){
                return Constant.GroupBuyConstant.OVER_LIMIT;
            }
            //当前商品的限量剩余
            Integer limitResidue = (Integer) map.get("limitResidue");
            if (limitResidue<=0){
                return GroupBuyEnum.UNDER_STOCK.getMessage();
            }
            //锁定商品库存
            limitResidue -=1;
            map.put("limitResidue",limitResidue);
            redisTemplate.opsForHash().putAll("group_goods:" + record.getGroupBuyItemId(),map);
            //创建订单
            String orderId = idWorker.nextId()+"";
            TbGroupOrder order = createGroupOrder(record.getGroupBuyItemId(),uid, map, orderId,Constant.GroupBuyConstant.NOT_HEADER,code);
            //拉起支付
            String html = pullUpToPay(map, orderId);
            return html;

        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            log.info("进程结束,开始释放锁...");
            //释放锁
            mutex.release();
        }
       return null;
    }

    /**
     * 拉起支付
     * @param item
     *
     * @param orderId
     * @return
     */
    private String pullUpToPay(Map item,String orderId) {
        PayVo payVo = new PayVo();
        payVo.setNotify_url(Constant.aliPay.NOTIFY_URL+"groupPaySuccess");
        payVo.setOut_trade_no(orderId);
        payVo.setSubject((String) item.get("goodsName"));
        payVo.setTotal_amount(item.get("groupPrice").toString());
        String html = alipayFeign.groupAilPay(payVo);
        return html;
    }

    /**
     * 创建拼团订单
     *
     * @param itemId
     * @param uid
     * @param item
     * @param orderId
     * @return
     */
    private TbGroupOrder createGroupOrder(Long itemId, Long uid, Map item, String orderId, String isHeader, String code) {
        TbGroupOrder order = new TbGroupOrder();
        order.setGoodsId(Long.parseLong(item.get("goodsId").toString()));
        order.setOrderId(orderId);
        order.setCreateTime(new Date());
        order.setIsHeader(isHeader);
        order.setStatus(Constant.OrderStatus.STATUS_ONE.toString());
        order.setItemId(itemId);
        order.setUserId(uid);
        order.setUpdateTime(new Date());
        order.setPayMoney((BigDecimal) item.get("groupPrice"));
        order.setInvitationCode(code);
        //将生成的订单id存入redis
        redisTemplate.opsForValue().set("user_order:"+orderId,"",Constant.OrderStatus.STATUS_TWO, TimeUnit.MINUTES);
        rabbitTemplate.convertAndSend(Constant.GroupBuyConstant.ADD_ORDER_QUEUE,"",order);
       //orderMapper.addGroupOrder(order);// 添加订单
        return order;
    }


    /**
     * 销毁curator客户端
     */
    @PreDestroy
    public void destroy(){
        CloseableUtils.closeQuietly(curatorFramework);
    }
}
